using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

public class LevelEditorManager : MonoBehaviour
{

    public enum STATE_EDITOR { DECORS, ENEMYS , TRAPS };

    public List<List<Tile>> tiles = new List<List<Tile>>();
    public GameObject baseTile;
    public GameObject baseEnemy;
    public GameObject baseDalle;
    public GameObject basePique;
    public GameObject baseLance;
    public GameObject baseBonus;
    public Vector3 startPos;
    public int nbTileX = 13;
    public int nbTileY = 7;
    public Tile currentTileSelected;
    public STATE_EDITOR stateEditor;
    public List<Enemy> enemyToSave;
    public List<Trap> trapToSave;
    public int nbPassages;
    public Vector2 archeoStartPos;

    public string fileName;

	// Use this for initialization
	void Start () {
        CreationMap();
	}

    void CreationMap()
    {
        //New Map
        if (fileName == "")
        {
            for (int i = 0; i < nbTileX; ++i)
            {
                List<Tile> tile = new List<Tile>();
                for (int j = 0; j < nbTileY; ++j)
                {
                    GameObject newTile = Instantiate(baseTile) as GameObject;
                    newTile.transform.position = new Vector3(startPos.x + i * newTile.collider.bounds.size.x, -10, startPos.z + j * newTile.collider.bounds.size.z);
                    tile.Add(newTile.GetComponent<Tile>());
                    newTile.GetComponent<Tile>().editor = true;
                }

                tiles.Add(tile);
            }
        }

        //Load Decors
        else
        {
            DeserializeDecors(fileName);
        }        
    }    

    public Tile GetTileAt(Vector2 pos)
    {
        return tiles[(int)pos.x][(int)pos.y];
    }

    //On GUI
    void OnGUI()
    {
        //Add colonne in map
        if (GUI.Button(new Rect(10, 10, 50, 50), "Add Col"))
        {
            List<Tile> tile = new List<Tile>();
            for (int j = 0; j < nbTileY; ++j)
            {
                GameObject newTile = Instantiate(baseTile) as GameObject;
                newTile.transform.position = new Vector3(startPos.x + nbTileX * newTile.collider.bounds.size.x, -10, startPos.z + j * newTile.collider.bounds.size.z);
                tile.Add(newTile.GetComponent<Tile>());
                newTile.GetComponent<Tile>().editor = true;
            }

            tiles.Add(tile);
            ++nbTileX;
        }

        //Add line in map
        if (GUI.Button(new Rect(10, 100, 50, 50), "Add Line"))
        {
            for (int i = 0; i < nbTileX; ++i)
            {
                List<Tile> tile = tiles[i];
                               
                GameObject newTile = Instantiate(baseTile) as GameObject;
                newTile.transform.position = new Vector3(startPos.x + i * newTile.collider.bounds.size.x, -10, startPos.z + nbTileY * newTile.collider.bounds.size.z);
                tile.Add(newTile.GetComponent<Tile>());
                newTile.GetComponent<Tile>().editor = true;
            }

            ++nbTileY;
        }

        //Save Button
        if(GUI.Button(new Rect(10, 160, 50, 50), "Save"))
        {
            Save();
        }
    }

    //Save
    public void Save()
    {
        XMLOutStream stream = new XMLOutStream();

        //Translate in XML format
        stream.Prolog("utf-8")

            .Start("LevelInfo")
            .Content("sizeX", nbTileX)
            .End();

        stream.Content("sizeY", nbTileY)
        .End();

        stream.Content("nbPassages", nbPassages)
        .End();

            stream.Content("archoStartPos", archeoStartPos)
            .End()

            .End()

            .Start("Tiles");
        foreach (List<Tile> list in tiles)
        {
            foreach (Tile tile in list)
            {
                stream.Start("Tile")
                    .Content("Type", tile.type.ToString())
                    .Content("Orientation", tile.transform.rotation.eulerAngles.y)
                    .Content("IndexTex", tile.indexTexture);
                    
                stream.End();
            }
        }
        stream.End();

        stream.Start("Enemys");
        foreach (Enemy enemy in enemyToSave)
        {
            enemy.Save(stream);
        }
        stream.End();

        Trap[] traps = FindObjectsOfType(typeof(Trap)) as Trap[];

            stream.Start("Traps");
        foreach (Trap trap in traps)
        {
            trap.Save(stream);
        }
        stream.End();

        //Save in File
        using (FileStream fs = File.Create("./Assets/Resources/XML/" + fileName + ".xml"))
        {
            AddText(fs, stream.Serialize(true));
        }
    }

    private static void AddText(FileStream fs, string value)
    {
        byte[] info = new UTF8Encoding(true).GetBytes(value);
        fs.Write(info, 0, info.Length);
    }


    //Load Level
    void DeserializeDecors(string name)
    {
        TextAsset txt = (TextAsset)Resources.Load("XML/" + name );
        XMLInStream stream = new XMLInStream(txt.text);

        GameObject go = new GameObject();
        go.name = "Tiles";
        go.transform.position = Vector3.zero;

        string type = "";

        stream.List("sizeX", delegate(XMLInStream stream2)
        {
            stream2.Content(out nbTileX);
        });

        stream.List("sizeY", delegate(XMLInStream stream2)
        {
            stream2.Content(out nbTileY);
        });

        stream.List("nbPassages", delegate(XMLInStream stream2)
        {
            stream2.Content(out nbPassages);
        });

        stream.List("archoStartPos", delegate(XMLInStream stream2)
        {
            stream2.Content(out archeoStartPos);
        });
        Debug.Log(archeoStartPos);

        stream.Start("Tiles");


        int x = 0;
        int y = 0;

        for (int i = 0; i < nbTileX; ++i)
        {
            List<Tile> tile = new List<Tile>();
            tiles.Add(tile);
        }
        

        stream.List("Tile", delegate(XMLInStream stream2)
        {           

            stream2.Content("Type", out type);

            GameObject newTile = Instantiate(baseTile) as GameObject;
            newTile.transform.parent = go.transform;

            for (int i = 0; i < (int)Const.TYPE_TILE.NB_TILE; ++i)
            {
                if (type == ((Const.TYPE_TILE)i).ToString())
                {
                    switch (i)
                    {
                        case (int)Const.TYPE_TILE.WALL:
                            newTile.transform.position = new Vector3(x, 0.5f, y);
                            newTile.gameObject.layer = Const.LAYER_WALL;
                            break;
                        case (int)Const.TYPE_TILE.GROUND:
                            newTile.transform.position = new Vector3(x, 0, y);
                            newTile.gameObject.layer = Const.LAYER_GROUND;
                            break;
                        case (int)Const.TYPE_TILE.PILE_OS:
                            newTile.transform.position = new Vector3(x, 0.5f, y);
                            break;
                        case (int)Const.TYPE_TILE.CAISSE:
                            newTile.transform.position = new Vector3(x, 0.5f, y);
                            break;
                        case (int)Const.TYPE_TILE.END:
                            newTile.transform.position = new Vector3(x, 0.5f, y);
                            break;
                    }

                    newTile.GetComponent<Tile>().SetType((Const.TYPE_TILE)i);
                    break;
                }
            }

            float angle;
            stream2.Content("Orientation", out angle);
            newTile.transform.Rotate(Vector3.up, angle);

            int indexTex = 0;
            stream2.Content("IndexTex", out indexTex);

            newTile.GetComponent<Tile>().SetIndexTexture(indexTex);
            newTile.GetComponent<Tile>().editor = true;
            tiles[x].Add(newTile.GetComponent<Tile>());           


            ++y;
            if (y >= nbTileY)
            {
                ++x;
                y = 0;
            }

        });

        stream.End();


        stream.Start("Enemys");
        enemyToSave = new List<Enemy>();

        int numEnemy = 0;
        stream.List("Enemy", delegate(XMLInStream stream2)
        {
            GameObject enemy = GameObject.Instantiate(baseEnemy) as GameObject;
            enemy.name = "Enemy" + numEnemy;
            enemy.GetComponent<Enemy>().Load(stream2);

            enemyToSave.Add(enemy.GetComponent<Enemy>());
            ++numEnemy;
        });

        stream.End();

        stream.Start("Traps");
        trapToSave = new List<Trap>();

        int numTrap = 0;
        stream.List("Trap", delegate(XMLInStream stream2)
        {
            int tmpType = 0;
            float tmpRota;
            GameObject trap=null;

            stream2.Content("typeTrap", out tmpType);
            stream2.Content("rotation", out tmpRota);
            Debug.Log(tmpRota);
            switch(tmpType)
            {
                case (int)Const.TRAP_TYPE.DALLE: 
                    trap = GameObject.Instantiate(baseDalle) as GameObject;
                    trap.GetComponent<Trap>().Load(stream2);
                    trapToSave.Add(trap.GetComponent<Trap>());
                    ++numTrap;
                    break;

                case (int)Const.TRAP_TYPE.PICK: 
                    trap = GameObject.Instantiate(basePique) as GameObject;
                    trap.GetComponent<Trap>().Load(stream2);
                    trapToSave.Add(trap.GetComponent<Trap>());
                    ++numTrap;
                    break;

                case (int)Const.TRAP_TYPE.LANCE: 
                    trap = GameObject.Instantiate(baseLance) as GameObject;
                    trap.GetComponent<Trap>().Load(stream2);
                    trapToSave.Add(trap.GetComponent<Trap>());
                    ++numTrap;
                    break;

                case (int)Const.TRAP_TYPE.BONUS:
                    trap = GameObject.Instantiate(baseBonus) as GameObject;
                    trap.GetComponent<Trap>().Load(stream2);
                    trapToSave.Add(trap.GetComponent<Trap>());
                    ++numTrap;
                    break;

            }
            trap.transform.Rotate(Vector3.up, tmpRota);
        });

        stream.End();

    }
}
